#include <gtest/gtest.h>
#include <string>
#include <unordered_map>
#include <MQ_Virtual_Engine/QueueData.hpp>

class QueueManagerTest : public ::testing::Test
{
protected:
    std::string test_db_path = "./test_queue.db";

    void SetUp() override
    {
        // Remove the database file if it exists before each test
        std::filesystem::remove(test_db_path);
    }

    void TearDown() override
    {
        // Clean up by removing the test database file after each test
        std::filesystem::remove(test_db_path);
    }
};

// Test the creation of QueueData
TEST_F(QueueManagerTest, CreateQueueData)
{
    //注意 json反序列化完成后，解析结果会有\n
    MY_MQ::QueueData queueData("test_queue", true, false, true, "{\"key\":\"value\"}");
    EXPECT_EQ(queueData._name, "test_queue");
    EXPECT_TRUE(queueData._durable);
    EXPECT_FALSE(queueData._exclusive);
    EXPECT_TRUE(queueData._autoDelete);
    EXPECT_EQ(queueData.GetArgs(""), "{\"key\":\"value\"}\n");
}

// Test QueueDataBuilder table creation and insertion
TEST_F(QueueManagerTest, QueueDataBuilderCreateInsert)
{
    MY_MQ::QueueDataBuilder builder(test_db_path);

    // Ensure table creation and insertion
    auto queueData = std::make_shared<MY_MQ::QueueData>("test_queue", true, false, true, "{\"key\":\"value\"}");
    bool insert_result = builder.insert(queueData);
    EXPECT_TRUE(insert_result);
}

// Test QueueDataBuilder recovery of data
TEST_F(QueueManagerTest, QueueDataBuilderRecovery)
{
    MY_MQ::QueueDataBuilder builder(test_db_path);

    // Insert a queue and recover it
    auto queueData = std::make_shared<MY_MQ::QueueData>("test_queue", true, false, true, "{\"key\":\"value\"}");
    builder.insert(queueData);

    auto recovered_data = builder.recovery();
    EXPECT_EQ(recovered_data.size(), 1);
    auto recovered_queue = recovered_data["test_queue"];
    EXPECT_EQ(recovered_queue->_name, "test_queue");
    EXPECT_TRUE(recovered_queue->_durable);
    EXPECT_FALSE(recovered_queue->_exclusive);
    EXPECT_TRUE(recovered_queue->_autoDelete);
    EXPECT_EQ(recovered_queue->GetArgs(""), "{\"key\":\"value\"}\n");
}

// Test QueueManager DeclareQueue and IsQueueExist
TEST_F(QueueManagerTest, QueueManagerDeclareQueue)
{
    MY_MQ::QueueManager manager(test_db_path);

    bool declare_result = manager.DeclareQueue("test_queue", true, false, true, "{\"key\":\"value\"}");
    EXPECT_TRUE(declare_result);
    EXPECT_TRUE(manager.IsQueueExist("test_queue"));
}

// Test QueueManager DeleteQueue
TEST_F(QueueManagerTest, QueueManagerDeleteQueue)
{
    MY_MQ::QueueManager manager(test_db_path);

    manager.DeclareQueue("test_queue", true, false, true, "{\"key\":\"value\"}");
    EXPECT_TRUE(manager.IsQueueExist("test_queue"));

    manager.DeleteQueue("test_queue");
    EXPECT_FALSE(manager.IsQueueExist("test_queue"));
}

// Test QueueManager SelectQueueData and GetAllQueueData
TEST_F(QueueManagerTest, QueueManagerGetQueueData)
{
    MY_MQ::QueueManager manager(test_db_path);

    manager.DeclareQueue("test_queue1", true, false, true, "{\"key\":\"value1\"}");
    manager.DeclareQueue("test_queue2", false, true, false, "{\"key\":\"value2\"}");

    auto queue1 = manager.SelectQueueData("test_queue1");
    EXPECT_EQ(queue1->_name, "test_queue1");
    EXPECT_TRUE(queue1->_durable);
    EXPECT_FALSE(queue1->_exclusive);
    EXPECT_TRUE(queue1->_autoDelete);
    EXPECT_EQ(queue1->GetArgs(""), "{\"key\":\"value1\"}\n");

    auto all_data = manager.GetAllQueueData();
    EXPECT_EQ(all_data.size(), 2);
}

// Test QueueManager clear and clearTmp
TEST_F(QueueManagerTest, QueueManagerClear)
{
    MY_MQ::QueueManager manager(test_db_path);

    manager.DeclareQueue("test_queue1", true, false, true, "{\"key\":\"value1\"}");
    manager.DeclareQueue("test_queue2", false, true, false, "{\"key\":\"value2\"}");

    EXPECT_EQ(manager.GetQueueCount(), 2);

    manager.clear();
    EXPECT_EQ(manager.GetQueueCount(), 0);
}

// Test QueueManager destructor with clearTmp
TEST_F(QueueManagerTest, QueueManagerDestructor)
{
    {
        MY_MQ::QueueManager manager(test_db_path);
        manager.DeclareQueue("test_queue1", false, false, true, "{\"key\":\"value1\"}");
    } // Destructor should be called here

    // Re-open and check the queue count
    MY_MQ::QueueManager manager(test_db_path);
    EXPECT_EQ(manager.GetQueueCount(), 0);
}

int main(int argc, char **argv)
{
    fmtlog::setHeaderPattern("{s} \t| {t} \t| {l} \t| {YmdHMS} \t| {g} \t| \n\t:");
    fmtlog::startPollingThread(12);
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
